package cn.tedu.controller;

import cn.tedu.pojo.Ad;
import cn.tedu.pojo.Coupon;
import cn.tedu.pojo.Item;
import cn.tedu.serivce.IAdService;
import cn.tedu.serivce.ICouponService;
import cn.tedu.serivce.IItemService;
import cn.tedu.util.AsyncTimeoutUtil;
import cn.tedu.vo.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 测试异步 线程池控制器
 * @author Kiven
 * @date 20220309
 */
@RestController
@RequestMapping("/web/api/completableFuture")
@Slf4j
public class TestAsyncCompletableFutureDemoController {
    @Autowired
    private IItemService itemService;
    @Autowired
    private ICouponService couponService;
    @Autowired
    private IAdService adService;

    @Autowired
    @Qualifier("asyncExecutor")
    private ThreadPoolTaskExecutor executorService;

    @RequestMapping("/home")
    public JsonResult findIndexList() {
        // TODO redis模块暂时不增加
        long startTime = System.currentTimeMillis();

        // 1. 并行启动所有异步任务
        CompletableFuture<List<Item>> itemFuture = CompletableFuture.supplyAsync(
                () -> itemService.getItemList(), executorService
        ).exceptionally(e -> {
            log.error("商品查询异常", e);
            return Arrays.asList(); // 降级返回空列表
        });

        CompletableFuture<List<Coupon>> couponFuture = CompletableFuture.supplyAsync(
                () -> couponService.getCoupon(), executorService
        ).exceptionally(e -> {
            log.error("优惠券查询异常", e);
            return Arrays.asList();
        });


        // JDK8原生不支持CompletableFuture超时控制  以下写法是JDK9的
        //CompletableFuture<List<Ad>> adFuture = CompletableFuture.supplyAsync(
        //                () -> adService.getAdList(), executorService
        //        ).orTimeout(3, TimeUnit.SECONDS) // 设置超时
        //        .exceptionally(e -> {
        //            return Arrays.asList();
        //        });
        //JDK8 只能自己设置工具类
        CompletableFuture<List<Ad>> adFuture = AsyncTimeoutUtil.withTimeout(
                () -> adService.getAdList(),
                3, TimeUnit.SECONDS,
                executorService
        ).exceptionally(e -> {
            if (e.getCause() instanceof TimeoutException) {
                log.error("广告查询超时", e);
            } else {
                log.error("广告查询异常", e);
            }
            return Collections.emptyList();
        });


        // 2. 合并结果（非阻塞等待）
        Map<String, Object> resultMap = new HashMap<>();
        CompletableFuture.allOf(itemFuture, couponFuture, adFuture)
                .thenRun(() -> {
                    resultMap.put("itemList", itemFuture.join());
                    resultMap.put("couponList", couponFuture.join());
                    resultMap.put("adList", adFuture.join());
                }).join(); // 同步等待结果聚合完成

        log.debug("总计用时:{}ms", System.currentTimeMillis() - startTime);
        return new JsonResult(resultMap);
    }
}
